#include "catch.hpp"
#include "ACEtk.hpp"
#include <map>

using namespace njoy::ACEtk;

extern std::array< double, 94 > refIndVarIncoherentFF;
extern std::array< double, 94 > refIncoherentFF;


SCENARIO( "Test interpretation::EPRdata::Incoherent" ){
  auto table = Table( njoy::utility::slurpFileToMemory( "1000.14p" ) );

  GIVEN( "An ACE Table for 1000.14p" ){
    const auto eprdata = interpretation::EPR( std::move(table) );
    const auto incoh = eprdata.incoherent();
    WHEN( "Querying for the energy grid for the incoherent scattering cross sections" ) {
      const std::map< int, double > referencePhotonEnergies{
	{   0, 1.000000000000E-06 },
	{  64, 8.013002999974E-06 },
	{ 129, 1.017127000001E-05 },
	{ 194, 1.167710000005E-05 },
	{ 259, 1.249504000002E-05 },
	{ 324, 2.788451999999E-05 },
	{ 389, 3.101247999991E-03 },
	{ 454, 7.413102000002E-01 },
        { 519, 2.745299999992E+00 },
	{ 584, 7.943300000026E+01 },
	{ 646, 1.000000000000E+05 } };
      
      const auto energies = incoh.energies();
      for ( const auto& pair : referencePhotonEnergies ){
	const auto index = pair.first;
	const auto reference = pair.second;
	REQUIRE( energies[ index ].value == Approx( reference ).epsilon( 1e-8 ) );
      }
    }
    
    WHEN( "Querying for the incoherent scattering cross sections" ){
      const std::map< int, double > referenceIncoherentXS{
	{   0, 9.562300000011E-08 },
	{  65, 6.233095862891E-06 },
	{ 130, 9.913960683988E-06 },
	{ 195, 1.305571253645E-05 },
	{ 260, 1.494693970558E-05 },
	{ 325, 7.594369400331E-05 },
	{ 390, 3.997974532085E-01 },
	{ 455, 2.356200069564E-01 },
	{ 520, 1.196748005439E-01 },
	{ 585, 9.876644877527E-03 },
	{ 646, 1.704199999997E-05 } };
      
      const auto incoherentScatteringXS = incoh.crossSection();
      for ( const auto& pair : referenceIncoherentXS ){
	const auto index = pair.first;
	const auto reference = pair.second;
	REQUIRE( incoherentScatteringXS[ index ].value == Approx( reference ) );
      }
    }
    
    const auto incohff = incoh.formFactors();    
    WHEN( "Querying for the independant variable for the photon incoherent form factors" ) {
      const auto var = incohff.scatteringCosines();
      auto compairs = ranges::view::zip( refIndVarIncoherentFF, var );
      for( const auto pair : compairs ){
	REQUIRE( pair.first == Approx( pair.second ) );
      }
    }

    WHEN( "Querying for the photon incoherent form factors" ) {
      const auto differential = incohff.differential();
      auto compairs = ranges::view::zip( refIncoherentFF, differential );
      for( const auto pair : compairs ){
	REQUIRE( pair.first == Approx( pair.second ) );
      }
    }
  }
}

std::array< double, 94 > refIndVarIncoherentFF = {{
    0.000000000000E+00, 1.000000000000E-07, 1.000000000000E-06,
    1.000000000000E-05, 1.000000000000E-04, 1.000000000000E-03,
    5.000000000000E-03, 1.000000000000E-02, 1.500000000000E-02,
    2.000000000000E-02, 2.500000000000E-02, 3.000000000000E-02,
    3.750000000000E-02, 4.000000000000E-02, 4.750000000000E-02,
    5.000000000000E-02, 5.875000000000E-02, 6.625000000000E-02,
    7.000000000000E-02, 7.875000000000E-02, 8.000000000000E-02,
    8.625000000000E-02, 9.000000000000E-02, 9.750000000000E-02,
    1.000000000000E-01, 1.062500000000E-01, 1.156300000000E-01,
    1.250000000000E-01, 1.359400000000E-01, 1.453100000000E-01,
    1.500000000000E-01, 1.609400000000E-01, 1.703100000000E-01,
    1.750000000000E-01, 1.875000000000E-01, 2.000000000000E-01,
    2.125000000000E-01, 2.218800000000E-01, 2.289100000000E-01,
    2.359400000000E-01, 2.429700000000E-01, 2.500000000000E-01,
    2.625000000000E-01, 2.718800000000E-01, 2.789100000000E-01,
    2.906300000000E-01, 2.929700000000E-01, 3.000000000000E-01,
    3.179700000000E-01, 3.250000000000E-01, 3.330100000000E-01,
    3.497600000000E-01, 3.625000000000E-01, 3.677000000000E-01,
    3.892300000000E-01, 4.000000000000E-01, 4.250000000000E-01,
    4.437500000000E-01, 4.500000000000E-01, 4.718800000000E-01,
    5.000000000000E-01, 5.250000000000E-01, 5.625000000000E-01,
    6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01,
    7.500000000000E-01, 8.000000000000E-01, 8.750000000000E-01,
    9.000000000000E-01, 1.000000000000E+00, 1.125000000000E+00,
    1.250000000000E+00, 1.437500000000E+00, 1.500000000000E+00,
    1.750000000000E+00, 2.000000000000E+00, 2.500000000000E+00,
    3.000000000000E+00, 3.500000000000E+00, 4.000000000000E+00,
    5.000000000000E+00, 6.000000000000E+00, 7.000000000000E+00,
    8.000000000000E+00, 1.000000000000E+01, 1.500000000000E+01,
    2.000000000000E+01, 5.000000000000E+01, 8.000000000000E+01,
    1.000000000000E+02, 1.000000000000E+03, 1.000000000000E+06,
    1.000000000000E+09 }};

std::array< double, 94 > refIncoherentFF = {{
    0.000000000000E+00, 4.409700000000E-13, 4.409700000000E-11,
    4.409700000000E-09, 4.409700000000E-07, 4.409700000000E-05,
    1.102425000000E-03, 4.409700000000E-03, 9.887600000000E-03,
    1.749400000000E-02, 2.716600000000E-02, 3.882600000000E-02,
    5.983670000000E-02, 6.772900000000E-02, 9.383850000000E-02,
    1.033100000000E-01, 1.391020000000E-01, 1.726290000000E-01,
    1.902300000000E-01, 2.329580000000E-01, 2.392320000000E-01,
    2.710060000000E-01, 2.903800000000E-01, 3.294640000000E-01,
    3.425600000000E-01, 3.752390000000E-01, 4.238310000000E-01,
    4.713000000000E-01, 5.245410000000E-01, 5.678810000000E-01,
    5.887300000000E-01, 6.347230000000E-01, 6.712280000000E-01,
    6.885000000000E-01, 7.310720000000E-01, 7.688400000000E-01,
    8.019520000000E-01, 8.240260000000E-01, 8.392010000000E-01,
    8.530840000000E-01, 8.658780000000E-01, 8.776800000000E-01,
    8.961610000000E-01, 9.082310000000E-01, 9.163850000000E-01,
    9.283980000000E-01, 9.305910000000E-01, 9.368600000000E-01,
    9.502770000000E-01, 9.546510000000E-01, 9.592280000000E-01,
    9.673380000000E-01, 9.723280000000E-01, 9.741820000000E-01,
    9.804080000000E-01, 9.829800000000E-01, 9.875650000000E-01,
    9.901100000000E-01, 9.908580000000E-01, 9.930070000000E-01,
    9.950200000000E-01, 9.962740000000E-01, 9.975580000000E-01,
    9.983700000000E-01, 9.989660000000E-01, 9.994100000000E-01,
    9.995910000000E-01, 9.997600000000E-01, 9.998670000000E-01,
    9.999000000000E-01, 9.999500000000E-01, 9.999710000000E-01,
    9.999900000000E-01, 9.999980000000E-01, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00, 1.000000000000E+00, 1.000000000000E+00,
    1.000000000000E+00 }};
